import cv2
import os
import numpy as np
import _thread

import time
import tkinter as tk
# from tkinter import filedialog#文件控件
from PIL import Image#图像控件
# from PIL import ImageTk#图像控件
# import threading#多线程

#global var setting
subjects = ["zyn", "wht", "ozc", "new_people1", "new_people2","new_people3","new_people4","new_people5","new_people6","new_people7"]
#加载OpenCV人脸检测分类器Haar
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

mask_cascade = cv2.CascadeClassifier('no_mask_detect_cascade.xml')

window = tk.Tk()
window.title('人脸识别系统')
sw = window.winfo_screenwidth()#获取屏幕宽
sh = window.winfo_screenheight()#获取屏幕高
wx = 280
wh = 150
window.geometry("%dx%d+%d+%d" %(wx,wh,(sw-wx)/2 + 300,(sh-wh)/2))#窗口至指定位置
canvas = tk.Canvas(window,bg='#c4c2c2',height=wh,width=wx) #绘制画布
canvas.pack()


def detect_face(img):
    #将测试图像转换为灰度图像，因为opencv人脸检测器需要灰度图像
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
    #检测多尺度图像，返回值是一张脸部区域信息的列表（x,y,宽,高）
    faces = face_cascade.detectMultiScale(
        gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(50, 50) #人脸的最小范围，如果比20*20像素小忽略
        )

    # 如果未检测到面部，则返回原始图像
    if (len(faces) == 0):
        return None, None, None
    #mask detection
    
    #目前假设只有一张脸，xy为左上角坐标，wh为矩形的宽高
    (x, y, w, h) = faces[0]
    
    no_mask = mask_cascade.detectMultiScale(
        gray[y:y + w, x:x + h],
        scaleFactor  = 1.01,
        minNeighbors = 4)
    
    #返回图像的正面部分
    return gray[y:y + w, x:x + h], faces[0], no_mask


#根据给定的（x，y）坐标和宽度高度在图像上绘制矩形
def draw_rectangle(img, rect):
    (x, y, w, h) = rect
    cv2.rectangle(img, (x, y), (x + w, y + h), (128, 128, 0), 2)

# 根据给定的（x，y）坐标标识出人名
def draw_text(img, text, x, y, color):
    if(color == "GREEN"):
        cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (128, 128, 0), 2)
    elif(color == "RED"):
        cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2)

# 此函数识别传递的图像中的人物并在检测到的脸部周围绘制一个矩形及其名称
def predict(test_img):
    #生成图像的副本，这样就能保留原始图像
    img = test_img.copy()
    #检测人脸
    face, rect, no_mask = detect_face(img)
    try:
        #预测人脸
        label = face_recognizer.predict(face)
        # 在检测到的脸部周围画一个矩形
        draw_rectangle(img, rect)
        if label[1]<70:
            # 获取由人脸识别器返回的相应标签的名称
            label_text = subjects[label[0]-1]
            # 标出预测的名字
            draw_text(img, label_text,  rect[0], rect[1] - 15, "GREEN")
            draw_text(img, "Identity Confirmed!",  rect[0], rect[1] - 40, "GREEN")
            #draw_text(img, "WEAR MASK", 100, 100)
        else:
            # 标出预测的名字
            draw_text(img, "WRONG PEOPLE",  rect[0], rect[1] - 5, "RED")
            #draw_text(img, "WEAR MASK", 100, 100)

        if (len(no_mask) != 0):
            #draw_rectangle(img, no_mask[0])
            draw_text(img, "please wear mask!!!",  20, 20, "RED")
        
    except Exception as err:
        print(err)
    #print(label)   
    #返回预测的图像
    return img

def Load_face_model():
    face_recognizer = cv2.face.LBPHFaceRecognizer_create()
    face_recognizer.read("face_model.xml")
    return face_recognizer


def face_recognize_video():
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        print("cant initial camera")

    while (1):                   
        ret, frame = cap.read()
        if not ret:
            print("cant obtain image")
            break

        predicted_img = predict(frame)
        draw_text(predicted_img, "press ESC or Q to exit", 20, 450, "RED")
        cv2.imshow("predict1", predicted_img)

        Key = cv2.waitKey(1)
        if Key == 27 or Key == ord('q'):
            break
        
    cap.release()
    cv2.destroyAllWindows() 

face_recognizer = Load_face_model()

bt_start = tk.Button(window,text='识别人脸',height=2,width=18,command=face_recognize_video)
bt_start.place(x=50,y=20)

window.mainloop()